/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.bootstrap;
import static org.jboss.weld.util.Types.buildClassNameMap;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Decorated;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Intercepted;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.TransientReference;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.EventMetadata;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.InterceptionFactory;
import javax.enterprise.inject.spi.Interceptor;
import javax.enterprise.inject.spi.PassivationCapable;
import javax.enterprise.inject.spi.Producer;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Scope;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotated;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.bean.AbstractBean;
import org.jboss.weld.bean.AbstractClassBean;
import org.jboss.weld.bean.AbstractProducerBean;
import org.jboss.weld.bean.CommonBean;
import org.jboss.weld.bean.DecorableBean;
import org.jboss.weld.bean.DecoratorImpl;
import org.jboss.weld.bean.DisposalMethod;
import org.jboss.weld.bean.InterceptorImpl;
import org.jboss.weld.bean.NewBean;
import org.jboss.weld.bean.ProducerMethod;
import org.jboss.weld.bean.SessionBean;
import org.jboss.weld.bean.WeldDecorator;
import org.jboss.weld.bean.builtin.AbstractBuiltInBean;
import org.jboss.weld.bean.builtin.AbstractDecorableBuiltInBean;
import org.jboss.weld.bean.builtin.ee.EEResourceProducerField;
import org.jboss.weld.bean.interceptor.CdiInterceptorFactory;
import org.jboss.weld.bootstrap.api.Service;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.exceptions.AmbiguousResolutionException;
import org.jboss.weld.exceptions.DefinitionException;
import org.jboss.weld.exceptions.DeploymentException;
import org.jboss.weld.exceptions.UnproxyableResolutionException;
import org.jboss.weld.injection.producer.AbstractMemberProducer;
import org.jboss.weld.injection.producer.BasicInjectionTarget;
import org.jboss.weld.interceptor.reader.PlainInterceptorFactory;
import org.jboss.weld.interceptor.spi.metadata.InterceptorClassMetadata;
import org.jboss.weld.interceptor.spi.model.InterceptionModel;
import org.jboss.weld.literal.DecoratedLiteral;
import org.jboss.weld.literal.InterceptedLiteral;
import org.jboss.weld.logging.BeanLogger;
import org.jboss.weld.logging.MessageCallback;
import org.jboss.weld.logging.ValidatorLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.metadata.cache.MetaAnnotationStore;
import org.jboss.weld.metadata.cache.StereotypeModel;
import org.jboss.weld.module.PlugableValidator;
import org.jboss.weld.security.GetDeclaredFieldsAction;
import org.jboss.weld.security.GetDeclaredMethodsAction;
import org.jboss.weld.util.AnnotatedTypes;
import org.jboss.weld.util.BeanMethods;
import org.jboss.weld.util.Beans;
import org.jboss.weld.util.Decorators;
import org.jboss.weld.util.InjectionPoints;
import org.jboss.weld.util.Proxies;
import org.jboss.weld.util.collections.Multimap;
import org.jboss.weld.util.collections.SetMultimap;
import org.jboss.weld.util.collections.WeldCollections;
import org.jboss.weld.util.reflection.Formats;
import org.jboss.weld.util.reflection.Reflections;
/**
* Checks a list of beans for DeploymentExceptions and their subclasses
*
* @author Nicklas Karlsson
* @author David Allen
* @author Jozef Hartinger
* @author Stuart Douglas
* @author Ales Justin
*/
public class Validator implements Service {
private final Set<PlugableValidator> plugableValidators;
public Validator(Set<PlugableValidator> plugableValidators) {
this.plugableValidators = plugableValidators;
}
protected void validateGeneralBean(Bean<?> bean, BeanManagerImpl beanManager) {
for (InjectionPoint ij : bean.getInjectionPoints()) {
validateInjectionPoint(ij, beanManager);
}
// Validate all pseudo-scoped beans, except for built-in beans and session beans which are proxied by the EJB container
if (!beanManager.isNormalScope(bean.getScope()) && !(bean instanceof AbstractBuiltInBean) && !(bean instanceof SessionBean)) {
validatePseudoScopedBean(bean, beanManager);
}
if (beanManager.isPassivatingScope(bean.getScope()) && !Beans.isPassivationCapableBean(bean)) {
throw ValidatorLogger.LOG.beanWithPassivatingScopeNotPassivationCapable(bean);
}
}
/**
* Validate an RIBean. This includes validating whether two beans specialize
* the same bean
*
* @param bean the bean to validate
* @param beanManager the current manager
* @param specializedBeans the existing specialized beans
*/
protected void validateRIBean(CommonBean<?> bean, BeanManagerImpl beanManager, Collection<CommonBean<?>> specializedBeans) {
validateGeneralBean(bean, beanManager);
if (bean instanceof NewBean) {
return;
}
if (bean instanceof DecorableBean) {
validateDecorators(beanManager, (DecorableBean<?>) bean);
}
if ((bean instanceof AbstractClassBean<?>)) {
AbstractClassBean<?> classBean = (AbstractClassBean<?>) bean;
// validate CDI-defined interceptors
if (classBean.hasInterceptors()) {
validateInterceptors(beanManager, classBean);
}
}
// for each producer bean validate its disposer method
if (bean instanceof AbstractProducerBean<?, ?, ?>) {
AbstractProducerBean<?, ?, ?> producerBean = Reflections.<AbstractProducerBean<?, ?, ?>> cast(bean);
if (producerBean.getProducer() instanceof AbstractMemberProducer<?, ?>) {
AbstractMemberProducer<?, ?> producer = Reflections.<AbstractMemberProducer<?, ?>> cast(producerBean
.getProducer());
if (producer.getDisposalMethod() != null) {
for (InjectionPoint ip : producer.getDisposalMethod().getInjectionPoints()) {
// pass the producer bean instead of the disposal method bean
validateInjectionPointForDefinitionErrors(ip, null, beanManager);
validateMetadataInjectionPoint(ip, null, ValidatorLogger.INJECTION_INTO_DISPOSER_METHOD);
validateEventMetadataInjectionPoint(ip);
validateInjectionPointForDeploymentProblems(ip, null, beanManager);
}
}
}
}
}
private void validateCustomBean(Bean<?> bean, BeanManagerImpl beanManager) {
validateGeneralBean(bean, beanManager);
if (!(bean instanceof PassivationCapable) && beanManager.isNormalScope(bean.getScope())) {
ValidatorLogger.LOG.beanNotPassivationCapable(bean);
}
}
private void validateInterceptors(BeanManagerImpl beanManager, AbstractClassBean<?> classBean) {
InterceptionModel interceptionModel = beanManager.getInterceptorModelRegistry().get(classBean.getAnnotated());
if (interceptionModel != null) {
Set<? extends InterceptorClassMetadata<?>> interceptors = interceptionModel.getAllInterceptors();
if (interceptors.size() > 0) {
boolean passivationCapabilityCheckRequired = beanManager.isPassivatingScope(classBean.getScope());
for (InterceptorClassMetadata<?> interceptorMetadata : interceptors) {
// in the case of CDI interceptors we only need to additionally validate passivation capability (if required)
if (interceptorMetadata.getInterceptorFactory() instanceof CdiInterceptorFactory<?> && passivationCapabilityCheckRequired) {
CdiInterceptorFactory<?> cdiInterceptorFactory = (CdiInterceptorFactory<?>) interceptorMetadata.getInterceptorFactory();
Interceptor<?> interceptor = cdiInterceptorFactory.getInterceptor();
boolean isSerializable = (interceptor instanceof InterceptorImpl) ? ((InterceptorImpl<?>) interceptor).isSerializable() : Beans.isPassivationCapableDependency(interceptor);
if (!isSerializable) {
throw ValidatorLogger.LOG.passivatingBeanWithNonserializableInterceptor(classBean, interceptor);
}
if (interceptor instanceof InterceptorImpl) {
beanManager = ((InterceptorImpl<?>) interceptor).getBeanManager();
}
for (InjectionPoint injectionPoint : interceptor.getInjectionPoints()) {
Bean<?> resolvedBean = beanManager.resolve(beanManager.getBeans(injectionPoint));
validateInterceptorDecoratorInjectionPointPassivationCapable(injectionPoint, resolvedBean, beanManager, classBean);
}
}
if (interceptorMetadata.getInterceptorFactory() instanceof PlainInterceptorFactory<?>) {
PlainInterceptorFactory<?> factory = (PlainInterceptorFactory<?>) interceptorMetadata.getInterceptorFactory();
Class<?> interceptorClass = interceptorMetadata.getJavaClass();
if (passivationCapabilityCheckRequired && !Reflections.isSerializable(interceptorClass)) {
throw ValidatorLogger.LOG.passivatingBeanWithNonserializableInterceptor(this, interceptorClass.getName());
}
// if we can't get to the interceptor's BeanManager, we will use the bean's BM instead
InjectionTarget<?> injectionTarget = factory.getInjectionTarget();
if (injectionTarget instanceof BasicInjectionTarget<?>) {
beanManager = ((BasicInjectionTarget<?>) injectionTarget).getBeanManager();
}
for (InjectionPoint injectionPoint : factory.getInjectionTarget().getInjectionPoints()) {
validateInjectionPoint(injectionPoint, beanManager);
if (passivationCapabilityCheckRequired) {
Bean<?> resolvedBean = beanManager.resolve(beanManager.getBeans(injectionPoint));
validateInterceptorDecoratorInjectionPointPassivationCapable(injectionPoint, resolvedBean, beanManager, classBean);
}
}
}
}
}
}
}
private void validateDecorators(BeanManagerImpl beanManager, DecorableBean<?> bean) {
if (!(beanManager.isPassivatingScope(bean.getScope()) || bean instanceof AbstractDecorableBuiltInBean<?>)) {
return;
}
List<Decorator<?>> decorators = bean.getDecorators();
if (decorators.isEmpty()) {
return;
}
for (Decorator<?> decorator : decorators) {
if (!Decorators.isPassivationCapable(decorator)) {
if (bean instanceof AbstractDecorableBuiltInBean<?>) {
throw ValidatorLogger.LOG.builtinBeanWithNonserializableDecorator(decorator, bean);
} else {
throw ValidatorLogger.LOG.passivatingBeanWithNonserializableDecorator(bean, decorator);
}
}
if (decorator instanceof DecoratorImpl) {
beanManager = ((DecoratorImpl<?>) decorator).getBeanManager();
}
for (InjectionPoint ij : decorator.getInjectionPoints()) {
if (!ij.isDelegate()) {
Bean<?> resolvedBean = beanManager.resolve(beanManager.getBeans(ij));
validateInterceptorDecoratorInjectionPointPassivationCapable(ij, resolvedBean, beanManager, bean);
}
}
}
}
/**
* Validate an injection point
*
* @param ij the injection point to validate
* @param beanManager the bean manager
*/
public void validateInjectionPoint(InjectionPoint ij, BeanManagerImpl beanManager) {
validateInjectionPointForDefinitionErrors(ij, ij.getBean(), beanManager);
validateMetadataInjectionPoint(ij, ij.getBean(), ValidatorLogger.INJECTION_INTO_NON_BEAN);
validateEventMetadataInjectionPoint(ij);
validateInjectionPointForDeploymentProblems(ij, ij.getBean(), beanManager);
}
/**
* Checks for definition errors associated with a given {@link InjectionPoint}
*/
public void validateInjectionPointForDefinitionErrors(InjectionPoint ij, Bean<?> bean, BeanManagerImpl beanManager) {
if (ij.getAnnotated().getAnnotation(New.class) != null && ij.getQualifiers().size() > 1) {
throw ValidatorLogger.LOG.newWithQualifiers(ij, Formats.formatAsStackTraceElement(ij));
}
if (ij.getType() instanceof TypeVariable<?>) {
throw ValidatorLogger.LOG.injectionPointWithTypeVariable(ij, Formats.formatAsStackTraceElement(ij));
}
// WELD-1739
if (ij.getMember() instanceof Executable && ij.getAnnotated().isAnnotationPresent(Named.class)
&& ij.getAnnotated().getAnnotation(Named.class).value().equals("")) {
Executable executable = (Executable) ij.getMember();
AnnotatedParameter<?> annotatedParameter = (AnnotatedParameter<?>) ij.getAnnotated();
if (!executable.getParameters()[annotatedParameter.getPosition()].isNamePresent()) {
// No parameters info available
throw ValidatorLogger.LOG.nonFieldInjectionPointCannotUseNamed(ij, Formats.formatAsStackTraceElement(ij));
}
}
if (ij.getAnnotated().isAnnotationPresent(Produces.class)) {
if (bean != null) {
throw BeanLogger.LOG.injectedFieldCannotBeProducer(ij.getAnnotated(), bean);
} else {
throw BeanLogger.LOG.injectedFieldCannotBeProducer(ij.getAnnotated(), Reflections.<AnnotatedField<?>>cast(ij.getAnnotated()).getDeclaringType());
}
}
boolean newBean = (bean instanceof NewBean);
if (!newBean) {
checkScopeAnnotations(ij, beanManager.getServices().get(MetaAnnotationStore.class));
}
checkFacadeInjectionPoint(ij, Instance.class);
checkFacadeInjectionPoint(ij, Event.class);
if (InterceptionFactory.class.equals(Reflections.getRawType(ij.getType())) && !(bean instanceof ProducerMethod<?, ?>)) {
throw ValidatorLogger.LOG.invalidInterceptionFactoryInjectionPoint(ij, Formats.formatAsStackTraceElement(ij));
}
for (PlugableValidator validator : plugableValidators) {
validator.validateInjectionPointForDefinitionErrors(ij, bean, beanManager);
}
}
public void validateMetadataInjectionPoint(InjectionPoint ij, Bean<?> bean, MessageCallback<DefinitionException> messageCallback) {
// metadata injection points
if (ij.getType().equals(InjectionPoint.class) && bean == null) {
throw messageCallback.construct(ij, Formats.formatAsStackTraceElement(ij));
}
if (ij.getType().equals(InjectionPoint.class) && !Dependent.class.equals(bean.getScope())) {
throw ValidatorLogger.LOG.injectionIntoNonDependentBean(ij, Formats.formatAsStackTraceElement(ij));
}
Class<?> rawType = Reflections.getRawType(ij.getType());
if (Bean.class.equals(rawType) || Interceptor.class.equals(rawType) || Decorator.class.equals(rawType)) {
if (bean == null) {
throw messageCallback.construct(ij, Formats.formatAsStackTraceElement(ij));
}
if (bean instanceof AbstractClassBean<?>) {
checkBeanMetadataInjectionPoint(bean, ij, AnnotatedTypes.getDeclaringAnnotatedType(ij.getAnnotated()).getBaseType());
}
if (bean instanceof ProducerMethod<?, ?>) {
ProducerMethod<?, ?> producerMethod = Reflections.cast(bean);
checkBeanMetadataInjectionPoint(bean, ij, producerMethod.getAnnotated().getBaseType());
}
}
}
public void validateEventMetadataInjectionPoint(InjectionPoint ip) {
if (EventMetadata.class.equals(ip.getType()) && ip.getQualifiers().contains(Default.Literal.INSTANCE)) {
throw ValidatorLogger.LOG.eventMetadataInjectedOutsideOfObserver(ip, Formats.formatAsStackTraceElement(ip));
}
}
/**
* Checks for deployment problems associated with a given {@link InjectionPoint}
*/
public void validateInjectionPointForDeploymentProblems(InjectionPoint ij, Bean<?> bean, BeanManagerImpl beanManager) {
if (ij.isDelegate()) {
return; // do not validate delegate injection points as these are special
}
Set<?> resolvedBeans = beanManager.getBeanResolver().resolve(beanManager.getBeans(ij));
if (!isInjectionPointSatisfied(ij, resolvedBeans, beanManager)) {
throw ValidatorLogger.LOG.injectionPointHasUnsatisfiedDependencies(
ij,
Formats.formatAnnotations(ij.getQualifiers()),
Formats.formatInjectionPointType(ij.getType()),
Formats.formatAsStackTraceElement(ij),
InjectionPoints.getUnsatisfiedDependenciesAdditionalInfo(ij, beanManager));
}
if (resolvedBeans.size() > 1) {
throw ValidatorLogger.LOG.injectionPointHasAmbiguousDependencies(
ij,
Formats.formatAnnotations(ij.getQualifiers()),
Formats.formatInjectionPointType(ij.getType()),
Formats.formatAsStackTraceElement(ij),
WeldCollections.toMultiRowString(resolvedBeans));
}
// Account for the case this is disabled decorator
if (!resolvedBeans.isEmpty()) {
Bean<?> resolvedBean = (Bean<?>) resolvedBeans.iterator().next();
if (beanManager.isNormalScope(resolvedBean.getScope())) {
UnproxyableResolutionException ue = Proxies.getUnproxyableTypeException(ij.getType(), resolvedBean, beanManager.getServices(), false);
if (ue != null) {
throw ValidatorLogger.LOG.injectionPointHasNonProxyableDependencies(ij, Formats.formatAsStackTraceElement(ij), ue);
}
}
if (bean != null && Beans.isPassivatingScope(bean, beanManager)) {
validateInjectionPointPassivationCapable(ij, resolvedBean, beanManager);
}
}
for (PlugableValidator validator : plugableValidators) {
validator.validateInjectionPointForDeploymentProblems(ij, bean, beanManager);
}
}
public void validateProducers(Collection<Producer<?>> producers, BeanManagerImpl beanManager) {
for (Producer<?> producer : producers) {
validateProducer(producer, beanManager);
}
}
public void validateProducer(Producer<?> producer, BeanManagerImpl beanManager) {
for (InjectionPoint injectionPoint : producer.getInjectionPoints()) {
validateInjectionPoint(injectionPoint, beanManager);
}
}
private void checkScopeAnnotations(InjectionPoint ij, MetaAnnotationStore metaAnnotationStore) {
Annotated annotated = ij.getAnnotated();
if (annotated instanceof EnhancedAnnotated<?, ?>) {
EnhancedAnnotated<?, ?> weldAnnotated = (EnhancedAnnotated<?, ?>) annotated;
Set<Annotation> scopes = weldAnnotated.getMetaAnnotations(Scope.class);
Set<Annotation> normalScopes = weldAnnotated.getMetaAnnotations(NormalScope.class);
for (Annotation annotation : scopes) {
logScopeOnInjectionPointWarning(ij, annotation);
}
for (Annotation annotation : normalScopes) {
logScopeOnInjectionPointWarning(ij, annotation);
}
} else {
for (Annotation annotation : annotated.getAnnotations()) {
if (hasScopeMetaAnnotation(annotation)) {
logScopeOnInjectionPointWarning(ij, annotation);
}
}
}
}
private void logScopeOnInjectionPointWarning(InjectionPoint ij, Annotation annotation) {
ValidatorLogger.LOG.scopeAnnotationOnInjectionPoint(annotation, ij, Formats.formatAsStackTraceElement(ij));
}
private boolean hasScopeMetaAnnotation(Annotation annotation) {
Class<? extends Annotation> annotationType = annotation.annotationType();
return annotationType.isAnnotationPresent(Scope.class) || annotationType.isAnnotationPresent(NormalScope.class);
}
private boolean isInjectionPointPassivationCapable(InjectionPoint ij, Bean<?> resolvedBean, BeanManagerImpl beanManager) {
if (!Beans.isPassivationCapableDependency(resolvedBean)) {
if (((ij.getMember() instanceof Field) && ij.isTransient())) {
return true;
}
if (ij.getAnnotated() instanceof AnnotatedParameter<?> && ij.getAnnotated().isAnnotationPresent(TransientReference.class)) {
return true;
}
return false;
}
return true;
}
public void validateInjectionPointPassivationCapable(InjectionPoint ij, Bean<?> resolvedBean, BeanManagerImpl beanManager) {
if (!isInjectionPointPassivationCapable(ij, resolvedBean, beanManager)) {
throw ValidatorLogger.LOG.injectionPointHasNonSerializableDependency(ij.getBean(), resolvedBean);
}
}
public void validateInterceptorDecoratorInjectionPointPassivationCapable(InjectionPoint ij, Bean<?> resolvedBean, BeanManagerImpl beanManager, Bean<?> bean) {
if (!isInjectionPointPassivationCapable(ij, resolvedBean, beanManager)) {
throw ValidatorLogger.LOG.interceptorDecoratorInjectionPointHasNonSerializableDependency(bean, ij.getBean(), resolvedBean);
}
}
public void validateDeployment(BeanManagerImpl manager, BeanDeployment deployment) {
validateDecorators(manager.getDecorators(), manager);
validateInterceptors(manager.getInterceptors(), manager);
validateBeans(manager.getBeans(), manager);
validateEnabledDecoratorClasses(manager, deployment);
validateEnabledInterceptorClasses(manager, deployment);
validateEnabledAlternativeStereotypes(manager, deployment);
validateEnabledAlternativeClasses(manager, deployment);
validateSpecialization(manager);
validateDisposalMethods(deployment.getBeanDeployer().getEnvironment());
validateObserverMethods(deployment.getBeanDeployer().getEnvironment().getObservers(), manager);
validateBeanNames(manager);
}
public void validateSpecialization(BeanManagerImpl manager) {
SpecializationAndEnablementRegistry registry = manager.getServices().get(SpecializationAndEnablementRegistry.class);
for (Entry<AbstractBean<?, ?>, Long> entry : registry.getBeansSpecializedInAnyDeploymentAsMap().entrySet()) {
if (entry.getValue() > 1) {
throw ValidatorLogger.LOG.beanSpecializedTooManyTimes(entry.getKey());
}
}
}
public void validateBeans(Collection<? extends Bean<?>> beans, BeanManagerImpl manager) {
final List<RuntimeException> problems = new ArrayList<RuntimeException>();
final Set<CommonBean<?>> specializedBeans = new HashSet<CommonBean<?>>();
for (Bean<?> bean : beans) {
validateBean(bean, specializedBeans, manager, problems);
}
if (!problems.isEmpty()) {
if (problems.size() == 1) {
throw problems.get(0);
} else {
throw new DeploymentException(problems);
}
}
}
protected void validateBean(Bean<?> bean, Collection<CommonBean<?>> specializedBeans, BeanManagerImpl manager, List<RuntimeException> problems) {
try {
if (bean instanceof CommonBean<?>) {
validateRIBean((CommonBean<?>) bean, manager, specializedBeans);
} else {
validateCustomBean(bean, manager);
}
} catch (RuntimeException e) {
problems.add(e);
}
}
public void validateInterceptors(Collection<? extends Interceptor<?>> interceptors, BeanManagerImpl manager) {
for (Interceptor<?> interceptor : interceptors) {
validateInterceptor(interceptor, manager);
}
}
protected void validateInterceptor(Interceptor<?> interceptor, BeanManagerImpl manager) {
if (interceptor instanceof InterceptorImpl<?>) {
EnhancedAnnotatedType<?> annotated = ((InterceptorImpl<?>) interceptor).getEnhancedAnnotated();
if (!BeanMethods.getObserverMethods(annotated).isEmpty() || !BeanMethods.getAsyncObserverMethods(annotated).isEmpty()) {
throw ValidatorLogger.LOG.interceptorsCannotHaveObserverMethods(interceptor);
}
if (!interceptor.getScope().equals(Dependent.class)) {
throw ValidatorLogger.LOG.interceptorOrDecoratorMustBeDependent(interceptor);
}
while (annotated != null && annotated.getJavaClass() != Object.class) {
if (!annotated.getDeclaredEnhancedMethods(Produces.class).isEmpty()) {
throw ValidatorLogger.LOG.interceptorsCannotHaveProducerMethods(interceptor);
}
if (!annotated.getDeclaredEnhancedFields(Produces.class).isEmpty()) {
throw ValidatorLogger.LOG.interceptorsCannotHaveProducerFields(interceptor);
}
if (!annotated.getDeclaredEnhancedMethodsWithAnnotatedParameters(Disposes.class).isEmpty()) {
throw ValidatorLogger.LOG.interceptorsCannotHaveDisposerMethods(interceptor);
}
annotated = annotated.getEnhancedSuperclass();
}
}
for (InjectionPoint injectionPoint : interceptor.getInjectionPoints()) {
validateInjectionPoint(injectionPoint, manager);
}
}
public void validateDecorators(Collection<? extends Decorator<?>> decorators, BeanManagerImpl manager) {
Set<CommonBean<?>> specializedBeans = new HashSet<CommonBean<?>>();
for (Decorator<?> decorator : decorators) {
validateDecorator(decorator, specializedBeans, manager);
}
}
protected void validateDecorator(Decorator<?> decorator, Collection<CommonBean<?>> specializedBeans, BeanManagerImpl manager) {
if (decorator.getDecoratedTypes().isEmpty()) {
throw ValidatorLogger.LOG.noDecoratedTypes(decorator);
}
if (!decorator.getScope().equals(Dependent.class)) {
throw ValidatorLogger.LOG.interceptorOrDecoratorMustBeDependent(decorator);
}
Decorators.checkDelegateType(decorator);
/*
* Validate decorators of facade built-in beans
*/
Type delegateType = decorator.getDelegateType();
if (delegateType instanceof ParameterizedType) {
ParameterizedType parameterizedDelegateType = (ParameterizedType) delegateType;
if (!Decorators.isPassivationCapable(decorator)) {
if (Instance.class.equals(parameterizedDelegateType.getRawType()) || Provider.class.equals(parameterizedDelegateType.getRawType())) {
throw ValidatorLogger.LOG.builtinBeanWithNonserializableDecorator(decorator, Instance.class.getName());
}
if (Event.class.equals(parameterizedDelegateType.getRawType())) {
throw ValidatorLogger.LOG.builtinBeanWithNonserializableDecorator(decorator, Event.class.getName());
}
}
}
if (decorator instanceof WeldDecorator<?>) {
EnhancedAnnotatedType<?> annotated = ((WeldDecorator<?>) decorator).getEnhancedAnnotated();
if (decorator instanceof DecoratorImpl<?>) {
// Discovered decorator bean - abstract methods and delegate injection point are validated during bean initialization
validateRIBean((CommonBean<?>) decorator, manager, specializedBeans);
// Following checks are not legal for custom decorator beans as we cannot rely on decorator bean class methods
if (!BeanMethods.getObserverMethods(annotated).isEmpty() || !BeanMethods.getAsyncObserverMethods(annotated).isEmpty()) {
throw ValidatorLogger.LOG.decoratorsCannotHaveObserverMethods(decorator);
}
while (annotated != null && annotated.getJavaClass() != Object.class) {
if (!annotated.getDeclaredEnhancedMethods(Produces.class).isEmpty()) {
throw ValidatorLogger.LOG.decoratorsCannotHaveProducerMethods(decorator);
}
if (!annotated.getDeclaredEnhancedFields(Produces.class).isEmpty()) {
throw ValidatorLogger.LOG.decoratorsCannotHaveProducerFields(decorator);
}
if (!annotated.getDeclaredEnhancedMethodsWithAnnotatedParameters(Disposes.class).isEmpty()) {
throw ValidatorLogger.LOG.decoratorsCannotHaveDisposerMethods(decorator);
}
annotated = annotated.getEnhancedSuperclass();
}
} else {
// Custom decorator bean
validateGeneralBean(decorator, manager);
Decorators.findDelegateInjectionPoint(annotated, decorator.getInjectionPoints());
}
}
}
public void validateBeanNames(BeanManagerImpl beanManager) {
SetMultimap<String, Bean<?>> namedAccessibleBeans = SetMultimap.newSetMultimap();
for (Bean<?> bean : beanManager.getAccessibleBeans()) {
if (bean.getName() != null) {
namedAccessibleBeans.put(bean.getName(), bean);
}
}
List<String> accessibleNamespaces = beanManager.getAccessibleNamespaces();
for (String name : namedAccessibleBeans.keySet()) {
validateBeanName(name, namedAccessibleBeans, accessibleNamespaces, beanManager);
}
}
protected void validateBeanName(String name, SetMultimap<String, Bean<?>> namedAccessibleBeans, List<String> accessibleNamespaces,
BeanManagerImpl beanManager) {
Set<Bean<?>> resolvedBeans = beanManager.getBeanResolver().<Object> resolve(Beans.removeDisabledBeans(namedAccessibleBeans.get(name), beanManager));
if (resolvedBeans.size() > 1) {
throw ValidatorLogger.LOG.ambiguousElName(name, resolvedBeans);
}
if (accessibleNamespaces.contains(name)) {
throw ValidatorLogger.LOG.beanNameIsPrefix(name);
}
}
private void validateEnabledInterceptorClasses(BeanManagerImpl beanManager, BeanDeployment deployment) {
BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();
if (beansXml != null && !beansXml.getEnabledInterceptors().isEmpty()) {
Set<String> interceptorBeanClasses = new HashSet<String>();
for (Interceptor<?> interceptor : beanManager.getDynamicAccessibleInterceptors()) {
interceptorBeanClasses.add(interceptor.getBeanClass().getName());
}
for (Metadata<String> interceptorClassName : beansXml.getEnabledInterceptors()) {
if (!interceptorBeanClasses.contains(interceptorClassName.getValue())) {
throw ValidatorLogger.LOG.interceptorClassDoesNotMatchInterceptorBean(interceptorClassName.getValue(), interceptorClassName.getLocation());
}
}
}
}
private void validateEnabledDecoratorClasses(BeanManagerImpl beanManager, BeanDeployment deployment) {
BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();
if (beansXml != null && !beansXml.getEnabledDecorators().isEmpty()) {
Set<String> decoratorBeanClasses = new HashSet<String>();
for (Decorator<?> bean : beanManager.getDynamicAccessibleDecorators()) {
decoratorBeanClasses.add(bean.getBeanClass().getName());
}
for (Metadata<String> decoratorClassName : beansXml.getEnabledDecorators()) {
if (!decoratorBeanClasses.contains(decoratorClassName.getValue())) {
throw ValidatorLogger.LOG.decoratorClassNotBeanClassOfDecorator(decoratorClassName.getValue(), WeldCollections.toMultiRowString(decoratorBeanClasses));
}
}
}
}
private void validateEnabledAlternativeStereotypes(BeanManagerImpl beanManager, BeanDeployment deployment) {
BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();
if (beansXml != null && !beansXml.getEnabledAlternativeStereotypes().isEmpty()) {
// prepare lookup structure
Map<String, Class<? extends Annotation>> loadedStereotypes = buildClassNameMap(beanManager.getEnabled().getAlternativeStereotypes());
for (Metadata<String> definition : beansXml.getEnabledAlternativeStereotypes()) {
Class<? extends Annotation> stereotype = loadedStereotypes.get(definition.getValue());
if (!beanManager.isStereotype(stereotype)) {
throw ValidatorLogger.LOG.alternativeStereotypeNotStereotype(definition);
}
if (!isAlternativeStereotype(beanManager, stereotype)) {
throw ValidatorLogger.LOG.alternativeStereotypeNotAnnotated(definition);
}
}
}
}
private void validateEnabledAlternativeClasses(BeanManagerImpl beanManager, BeanDeployment deployment) {
BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();
if (beansXml != null && !beansXml.getEnabledAlternativeClasses().isEmpty()) {
// prepare lookup structure
Map<String, Class<?>> loadedClasses = buildClassNameMap(beanManager.getEnabled().getAlternativeClasses());
// lookup structure for validation of alternatives
Multimap<Class<?>, Bean<?>> beansByClass = SetMultimap.newSetMultimap();
for (Bean<?> bean : beanManager.getDynamicAccessibleBeans()) {
if (!(bean instanceof NewBean)) {
beansByClass.put(bean.getBeanClass(), bean);
}
}
for (Metadata<String> definition : beansXml.getEnabledAlternativeClasses()) {
Class<?> enabledClass = loadedClasses.get(definition.getValue());
if (enabledClass.isAnnotation() || enabledClass.isInterface()) {
throw ValidatorLogger.LOG.alternativeBeanClassNotClass(definition);
} else {
if (!isAlternativeBean(enabledClass, beansByClass) && !isAlternativeCandidate(enabledClass, beanManager)) {
throw ValidatorLogger.LOG.alternativeBeanClassNotAnnotated(definition.getValue(), definition.getLocation());
}
}
}
}
}
private boolean isAlternativeCandidate(Class<?> enabledClass, BeanManagerImpl beanManager) {
// Note that the deployment would fail if any alternative <class> cannot be loaded
// <class> exists and is annotated with @Alternative or alternative stereotype
if (isAlternativeOrHasAlternativeStereotype(enabledClass, beanManager)) {
return true;
}
// <class> declares producer with alternative
// Intentionally do not process the class hierarchy -
for (Method declaredMethod : AccessController.doPrivileged(new GetDeclaredMethodsAction(enabledClass))) {
if (declaredMethod.isAnnotationPresent(Produces.class) && isAlternativeOrHasAlternativeStereotype(declaredMethod, beanManager)) {
return true;
}
}
for (Field declaredField : AccessController.doPrivileged(new GetDeclaredFieldsAction(enabledClass))) {
if (declaredField.isAnnotationPresent(Produces.class) && isAlternativeOrHasAlternativeStereotype(declaredField, beanManager)) {
return true;
}
}
return false;
}
private boolean isAlternativeOrHasAlternativeStereotype(AnnotatedElement annotatedElement, BeanManagerImpl beanManager) {
if (annotatedElement.isAnnotationPresent(Alternative.class)) {
return true;
}
for (Annotation annotation : annotatedElement.getAnnotations()) {
if (isAlternativeStereotype(beanManager, annotation.annotationType())) {
return true;
}
}
return false;
}
private boolean isAlternativeBean(Class<?> enabledClass, Multimap<Class<?>, Bean<?>> beansByClass) {
// check that the class is a bean class of at least one alternative
for (Bean<?> bean : beansByClass.get(enabledClass)) {
if (bean.isAlternative()) {
return true;
}
}
return false;
}
private static boolean isAlternativeStereotype(BeanManagerImpl beanManager, Class<? extends Annotation> stereotype) {
final StereotypeModel<? extends Annotation> model = beanManager.getServices().get(MetaAnnotationStore.class).getStereotype(stereotype);
if (model.isValid() && model.isAlternative()) {
return true;
}
return false;
}
private void validateDisposalMethods(BeanDeployerEnvironment environment) {
Set<DisposalMethod<?, ?>> beans = environment.getUnresolvedDisposalBeans();
if (!beans.isEmpty()) {
throw ValidatorLogger.LOG.disposalMethodsWithoutProducer(WeldCollections.toMultiRowString(beans));
}
}
protected void validateObserverMethods(Iterable<ObserverInitializationContext<?, ?>> observers, BeanManagerImpl beanManager) {
for (ObserverInitializationContext<?, ?> omi : observers) {
for (InjectionPoint ip : omi.getObserver().getInjectionPoints()) {
validateInjectionPointForDefinitionErrors(ip, ip.getBean(), beanManager);
validateMetadataInjectionPoint(ip, null, ValidatorLogger.INJECTION_INTO_NON_BEAN);
validateInjectionPointForDeploymentProblems(ip, ip.getBean(), beanManager);
}
}
}
private static void checkFacadeInjectionPoint(InjectionPoint injectionPoint, Class<?> type) {
Type injectionPointType = injectionPoint.getType();
if (injectionPointType instanceof Class<?> && type.equals(injectionPointType)) {
throw ValidatorLogger.LOG.injectionPointMustHaveTypeParameter(injectionPoint, Formats.formatAsStackTraceElement(injectionPoint));
}
if (injectionPointType instanceof ParameterizedType && !injectionPoint.isDelegate()) {
ParameterizedType parameterizedType = (ParameterizedType) injectionPointType;
if (type.equals(parameterizedType.getRawType())) {
if (parameterizedType.getActualTypeArguments()[0] instanceof TypeVariable<?>) {
throw ValidatorLogger.LOG.injectionPointWithTypeVariable(injectionPoint, Formats.formatAsStackTraceElement(injectionPoint));
}
if (parameterizedType.getActualTypeArguments()[0] instanceof WildcardType) {
throw ValidatorLogger.LOG.injectionPointHasWildcard(injectionPoint, Formats.formatAsStackTraceElement(injectionPoint));
}
}
}
}
public static void checkBeanMetadataInjectionPoint(Object bean, InjectionPoint ip, Type expectedTypeArgument) {
if (!(ip.getType() instanceof ParameterizedType)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
ParameterizedType parameterizedType = (ParameterizedType) ip.getType();
if (parameterizedType.getActualTypeArguments().length != 1) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
if (bean == null) {
throw ValidatorLogger.LOG.injectionIntoNonBean(ip, Formats.formatAsStackTraceElement(ip));
}
/*
* If an Interceptor instance is injected into a bean instance other than an interceptor instance, the container
* automatically detects the problem and treats it as a definition error.
*/
if (rawType.equals(Interceptor.class) && !(bean instanceof Interceptor<?>)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
/*
* If a Decorator instance is injected into a bean instance other than a decorator instance, the container automatically
* detects the problem and treats it as a definition error.
*/
if (rawType.equals(Decorator.class) && !(bean instanceof Decorator<?>)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
Set<Annotation> qualifiers = ip.getQualifiers();
if (qualifiers.contains(InterceptedLiteral.INSTANCE)) {
/*
* If a Bean instance with qualifier @Intercepted is injected into a bean instance other than an interceptor
* instance, the container automatically detects the problem and treats it as a definition error.
*/
if (!(bean instanceof Interceptor<?>)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointQualifier(Intercepted.class, Interceptor.class, ip, Formats.formatAsStackTraceElement(ip));
}
/*
* If the injection point is a field, an initializer method parameter or a bean constructor of an interceptor, with
* qualifier @Intercepted, then the type parameter of the injected Bean must be an unbounded wildcard.
*/
if (!rawType.equals(Bean.class)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
if (!Reflections.isUnboundedWildcard(typeArgument)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointTypeArgument(typeArgument, ip, Formats.formatAsStackTraceElement(ip));
}
}
if (qualifiers.contains(DecoratedLiteral.INSTANCE)) {
/*
* If a Bean instance with qualifier @Decorated is injected into a bean instance other than a decorator instance,
* the container automatically detects the problem and treats it as a definition error.
*/
if (!(bean instanceof Decorator<?>)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointQualifier(Decorated.class, Decorator.class, ip, Formats.formatAsStackTraceElement(ip));
}
Decorator<?> decorator = Reflections.cast(bean);
/*
* If the injection point is a field, an initializer method parameter or a bean constructor of a decorator, with
* qualifier @Decorated, then the type parameter of the injected Bean must be the same as the delegate type.
*/
if (!rawType.equals(Bean.class)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointType(ip.getType(), ip, Formats.formatAsStackTraceElement(ip));
}
if (!typeArgument.equals(decorator.getDelegateType())) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointTypeArgument(typeArgument, ip, Formats.formatAsStackTraceElement(ip));
}
}
if (qualifiers.contains(Default.Literal.INSTANCE)) {
/*
* If the injection point is a field, an initializer method parameter or a bean constructor, with qualifier
* @Default, then the type parameter of the injected Bean, Interceptor or Decorator must be the same as the type
* declaring the injection point.
*
* If the injection point is a producer method parameter then the type parameter of the injected Bean must be the
* same as the producer method return type.
*
* If the injection point is a disposer method parameter then the type parameter of the injected Bean must be the
* same as the disposed parameter.
*/
if (!expectedTypeArgument.equals(typeArgument)) {
throw ValidatorLogger.LOG.invalidBeanMetadataInjectionPointTypeArgument(typeArgument, ip, Formats.formatAsStackTraceElement(ip));
}
}
}
private static boolean isInjectionPointSatisfied(InjectionPoint ij, Set<?> resolvedBeans, BeanManagerImpl beanManager) {
if (ij.getBean() instanceof Decorator<?>) {
if (beanManager.getEnabled().isDecoratorEnabled(ij.getBean().getBeanClass())) {
return resolvedBeans.size() > 0;
} else {
return true;
}
} else {
return resolvedBeans.size() > 0;
}
}
/**
* Checks to make sure that pseudo scoped beans (i.e. @Dependent scoped beans) have no circular dependencies.
*/
private static void validatePseudoScopedBean(Bean<?> bean, BeanManagerImpl beanManager) {
if (bean.getInjectionPoints().isEmpty()) {
// Skip validation if there are no injection points (e.g. for classes which are not intended to be used as beans)
return;
}
reallyValidatePseudoScopedBean(bean, beanManager, new LinkedHashSet<Object>(), new HashSet<Bean<?>>());
}
/**
* checks if a bean has been seen before in the dependencyPath. If not, it
* resolves the InjectionPoints and adds the resolved beans to the set of
* beans to be validated
*/
private static void reallyValidatePseudoScopedBean(Bean<?> bean, BeanManagerImpl beanManager, Set<Object> dependencyPath, Set<Bean<?>> validatedBeans) {
// see if we have already seen this bean in the dependency path
if (dependencyPath.contains(bean)) {
// create a list that shows the path to the bean
List<Object> realDependencyPath = new ArrayList<Object>(dependencyPath);
realDependencyPath.add(bean);
throw ValidatorLogger.LOG.pseudoScopedBeanHasCircularReferences(WeldCollections.toMultiRowString(realDependencyPath));
}
if (validatedBeans.contains(bean)) {
return;
}
dependencyPath.add(bean);
for (InjectionPoint injectionPoint : bean.getInjectionPoints()) {
if (!injectionPoint.isDelegate()) {
dependencyPath.add(injectionPoint);
validatePseudoScopedInjectionPoint(injectionPoint, beanManager, dependencyPath, validatedBeans);
dependencyPath.remove(injectionPoint);
}
}
if (bean instanceof DecorableBean<?>) {
final List<Decorator<?>> decorators = Reflections.<DecorableBean<?>>cast(bean).getDecorators();
if (!decorators.isEmpty()) {
for (final Decorator<?> decorator : decorators) {
reallyValidatePseudoScopedBean(decorator, beanManager, dependencyPath, validatedBeans);
}
}
}
if (bean instanceof AbstractProducerBean<?, ?, ?> && !(bean instanceof EEResourceProducerField<?, ?>)) {
AbstractProducerBean<?, ?, ?> producer = (AbstractProducerBean<?, ?, ?>) bean;
if (!beanManager.isNormalScope(producer.getDeclaringBean().getScope()) && !producer.getAnnotated().isStatic()) {
reallyValidatePseudoScopedBean(producer.getDeclaringBean(), beanManager, dependencyPath, validatedBeans);
}
}
validatedBeans.add(bean);
dependencyPath.remove(bean);
}
private static void validatePseudoScopedInjectionPoint(InjectionPoint ij, BeanManagerImpl beanManager, Set<Object> dependencyPath, Set<Bean<?>> validatedBeans) {
Set<Bean<?>> resolved = beanManager.getBeans(ij);
Bean<?> bean = null;
try {
bean = beanManager.resolve(resolved);
} catch (AmbiguousResolutionException ex) {
throw ValidatorLogger.LOG.injectionPointHasAmbiguousDependencies(ij, Formats.formatAnnotations(ij.getQualifiers()),
Formats.formatInjectionPointType(ij.getType()),
Formats.formatAsStackTraceElement(ij),
WeldCollections.toMultiRowString(resolved));
}
if (bean != null) {
if (!(bean instanceof AbstractBuiltInBean<?>)) {
if (!ij.isDelegate()) {
boolean normalScoped = beanManager.isNormalScope(bean.getScope());
if (!normalScoped && !(bean instanceof SessionBean)) {
reallyValidatePseudoScopedBean(bean, beanManager, dependencyPath, validatedBeans);
}
}
}
}
}
@Override
public void cleanup() {
}
}